<?php

/**
 * This file is part of the Codizer package.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @copyright   Copyright (c) 2010 Advisa (http://www.advisa.fr)
 * @author      Codizer Core Team <team@codizer.org>
 * @package     Codizer
 */

class f_builder_RoutingBuilder
{
    private $routeNames = array();
    private $urls = array();

    /**
	 * @return f_builder_RoutingBuilder
	 */
	public static function getInstance()
	{
		return new self();
	}

    /**
     * Building routing file in webapp/config from all routing.xml files in modules
     * @return <type>
     */
    public function buildRouting()
    {
        $files = $this->getFiles();
        
        if(is_array($files) && count($files) > 0)
        {
            foreach($files as $file)
            {
                $e = explode(DS, $file);
                $moduleName = $e[count($e) - 3];
                $params[$moduleName] = $this->readRoutingFile($file);
            }

            $xmlContent = $this->makeXml($params);
            $this->writeXml($xmlContent);
            return true;
        }
        return false;
    }

    /**
     * Write routing.xml in webapp/config
     * @param string $content
     */
    private function writeXml($content)
    {
        $file = fopen(WEBAPP_DIR.DS.'config'.DS.'routing.xml', 'w');

        fwrite($file, $content);

        fclose($file);
    }

    /**
     * Create xml content from all routing.xml files
     * @param array $params
     * @return string
     */
    private function makeXml($params)
    {
        $xml = new XMLWriter();
        $xml->openMemory();
        $xml->setIndent(true);
        $xml->setIndentString('    ');
        $xml->startDocument('1.0', 'UTF-8');

        $xml->startElement('routes');

        foreach($params as $moduleName => $routes)
        {
            $xml->writeComment(' '.$moduleName.' routes ');
            foreach($routes as $route)
            {
                $xml->startElement('route');
                $xml->writeAttribute('name', $route['name']);
                $xml->writeAttribute('url', $route['url']);

                foreach($route['params'] as $param)
                {
                    $xml->startElement('param');
                    $xml->writeAttribute('name', $param['name']);
                    $xml->writeRaw($param['value']);
                    $xml->endElement();
                }

                $xml->endElement();
            }
        }

        $xml->writeComment(' default routes ');
        $xml->startElement('route');
        $xml->writeAttribute('name', 'defaultWithDocId');
        $xml->writeAttribute('url', '/:module/:action/:docId');
        $xml->endElement();
        $xml->startElement('route');
        $xml->writeAttribute('name', 'default');
        $xml->writeAttribute('url', '/:module/:action');
        $xml->endElement();

        $xml->endElement();
        $xml->endDocument();
        return $xml->outputMemory();
    }

    /**
     * read routing.xml file from modules dir
     * @param string $file
     * @return array
     */
    private function readRoutingFile($file)
    {
        $elements = f_xml_Xpath::getInstance($file)->getElementsFromXpath('route');

        if(is_array($elements) && count($elements) > 0)
        {
            $res = array();
            
            foreach($elements as $element)
            {
                /* @var $element f_xml_XmlElement */
                $name = $element->getAttributeValue('name');
                $url = $element->getAttributeValue('url');
                $params = $element->getSubElements('param');

                if(!in_array($name, $this->routeNames) && !in_array($url, $this->urls))
                {
                    $this->routeNames[] = $name;
                    $this->urls[] = $url;

                    $result = array();

                    $result['name'] = $name;
                    $result['url'] = $url;

                    if(is_array($params) && count($params) > 0)
                    {
                        foreach($params as $param)
                        {
                             /* @var $param f_xml_XmlElement */
                            $p = array();
                            $p['name'] = $param->getAttributeValue('name');
                            $p['value'] = $param->getContent();
                            $result['params'][] = $p;
                        }
                    }
                    else
                    {
                        throw new Exception('No parameters for route '.$name);
                    }
                }
                else
                {
                    throw new Exception('Route '.$name.' or url '.$url.' is duplicated');
                }
                $res[] = $result;
            }

            return $res;
        }
    }

    /**
     * Get routing.xml files path from modules and webapp dir
     * @return array
     */
    private function getFiles()
    {
        $modules = f_file_Resolver::getInstance()->fromDirectory(MODULES_DIR)->setRecursive(true)->setMask('config'.DS.'routing.xml')->find();
        $webapp = f_file_Resolver::getInstance()->fromDirectory(WEBAPP_MODULES_DIR)->setRecursive(true)->setMask('config'.DS.'routing.xml')->find();

        return array_merge($modules, $webapp);
    }
}